﻿using System.Collections.Generic;
namespace SGLisp
{
    public class FuncSeq
    {
        public List<IFuncSeqNode> FuncNodes = new List<IFuncSeqNode>();
        public bool IsRun { get { return isRun; } }
        bool isRun = false;
        bool isSeqEnd = false;
        public bool IsSeqEnd { get { return isSeqEnd; } }
        int CurNodeIndex = 0;
        bool isBlockNode = false;
        public System.Action<IFuncSeqNode> OnBeforeExec;
        public void AddFuncSeqNode(IFuncSeqNode node)
        {
            this.FuncNodes.Add(node);
        }
        public void ReSet()
        {
            this.isRun = false;
            this.isSeqEnd = false;
            this.CurNodeIndex = 0;
            this.isBlockNode = false;
            for (int i=0;i<FuncNodes.Count;i++)
            {
                if (FuncNodes[i].FuncSeqType == FuncSeqType.Block)
                {
                    ((IFuncSeqBlockNode)FuncNodes[i]).IsFinish = false;
                }
            }
        }
        public void Run()
        {
            this.CurNodeIndex = 0;
            this.isRun = true;
            this.isSeqEnd = false;
        }

        public void Update(Context context)
        {
            if (this.isRun == false || this.FuncNodes.Count == 0)
            {
                this.isRun = false;
                this.isSeqEnd = true;
                return;
            }
            bool hasRun = false;
            FuncNodes.ForEach((f)=> 
            {
                if (f.FuncSeqType == FuncSeqType.Block)
                {
                    IFuncSeqBlockNode block = (IFuncSeqBlockNode)f;
                   
                    if (block.IsExec)
                    {
                        f.Update(context);
                        hasRun = true;
                        if (block.IsFinish)
                        {
                            block.Exit();
                        }
                    }
                    
                }
            });
            if (hasRun ==false&&this.isSeqEnd)
            {
                this.isRun = false;
            }
            if (this.isSeqEnd)
            {
                return;
            }
            IFuncSeqNode funcNode = this.FuncNodes[this.CurNodeIndex];
            while (this.CurNodeIndex<this.FuncNodes.Count && !this.isBlockNode)
            {
                if (funcNode.FuncSeqType == FuncSeqType.NonBlock)
                {
                    this.CurNodeIndex++;
                    if (OnBeforeExec != null)
                    {
                        OnBeforeExec(funcNode);
                    }
                    funcNode.Exec(context);
                    this.isBlockNode = false;
                    if (this.CurNodeIndex >= this.FuncNodes.Count)
                    {
                        this.isSeqEnd = true;
                        return;
                    }
                    funcNode = this.FuncNodes[this.CurNodeIndex];
                }
                else
                {
                    this.isBlockNode = true;
                    if (OnBeforeExec != null)
                    {
                        OnBeforeExec(funcNode);
                    }
                    funcNode.Exec(context);
                }
            }
            if (this.isBlockNode && funcNode != null)
            {
                IFuncSeqBlockNode blockNode= (IFuncSeqBlockNode)funcNode;
                if (blockNode.IsFinish||blockNode.IsWait  == false)
                {
                    this.isBlockNode = false;
                    this.CurNodeIndex++;
                }
                if (this.CurNodeIndex == this.FuncNodes.Count)
                {
                    this.isSeqEnd = true;
                }
            }
        }

        public FuncSeq Clone()
        {
            FuncSeq newFuncSeq = new FuncSeq();
            for (int i=0;i<this.FuncNodes.Count;i++)
            {
                IFuncSeqNode seqNode = this.FuncNodes[i];
                newFuncSeq.FuncNodes.Add(seqNode.Clone());
            }
            return newFuncSeq;
        }

        public void Stop()
        {
            this.ReSet();
            for (int i = 0; i < FuncNodes.Count; i++)
            {
                if (FuncNodes[i].FuncSeqType == FuncSeqType.Block)
                {
                    ((IFuncSeqBlockNode)FuncNodes[i]).Stop();
                }
            }
        }

    }
}
